package com.example.provider.log.collector;

import com.example.api.common.log.LogCollector;
import com.example.api.common.log.LogEvent;
import com.example.api.common.log.LogProcessor;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;

@Slf4j
@Component
public class DefaultLogCollector implements LogCollector {
    private static final int QUEUE_CAPACITY = 10000;
    private static final int BATCH_SIZE = 100;
    private static final long POLL_TIMEOUT = 100L;
    
    private BlockingQueue<LogEvent> queue;
    private volatile boolean running = true;

    @Resource
    private LogProcessor logProcessor;
    
    @PostConstruct
    public void init() {
        queue = new LinkedBlockingQueue<>(QUEUE_CAPACITY);
        startProcessingThread();
    }
    
    private void startProcessingThread() {
        Thread processorThread = new Thread(() -> {
            while (running) {
                try {
                    processLogs();
                } catch (Exception e) {
                    log.error("Error processing logs", e);
                }
            }
        });
        processorThread.setName("log-processor");
        processorThread.setDaemon(true);
        processorThread.start();
    }
    
    private void processLogs() {
        try {
            List<LogEvent> batch = new ArrayList<>(BATCH_SIZE);
            queue.drainTo(batch, BATCH_SIZE);
            
            if (!batch.isEmpty()) {
                logProcessor.process(batch);
            } else {
                // If no events in batch, wait for a single event
                LogEvent event = queue.poll(POLL_TIMEOUT, TimeUnit.MILLISECONDS);
                if (event != null) {
                    logProcessor.process(Collections.singletonList(event));
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("Log processing interrupted", e);
        }
    }
    
    @Override
    public void collect(LogEvent event) {
        if (event == null) {
            return;
        }
        
        boolean offered = queue.offer(event);
        if (!offered) {
            log.warn("Log queue is full, event dropped: {}", event);
        }
    }
    
    public void shutdown() {
        running = false;
    }
}
